package com.lagou.edu.mvcframework.pojo;

import com.lagou.edu.mvcframework.annotations.Security;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;


/**
 * 封装handler方法相关的信息
 */
public class Handler {

    private Object controller; // method.invoke(obj,)

    private Method method;

    private Pattern pattern; // spring中url是支持正则的

    private Map<String, Integer> paramIndexMapping; // 参数顺序,是为了进行参数绑定，key是参数名，value代表是第几个参数 <name,2>

    private DualKeyMap<String, Integer, Object> params;


    public Handler(Object controller, Method method, Pattern pattern) {
        this.controller = controller;
        this.method = method;
        this.pattern = pattern;
        paramIndexMapping = new HashMap<>();
        this.params = new DualKeyMap<>();
    }

    public Object getController() {
        return controller;
    }

    public void setController(Object controller) {
        this.controller = controller;
    }

    public Method getMethod() {
        return method;
    }

    public void setMethod(Method method) {
        this.method = method;
    }

    public Pattern getPattern() {
        return pattern;
    }

    public void setPattern(Pattern pattern) {
        this.pattern = pattern;
    }

    public void setParam(String name, Object val) {
        params.put(name, getParamIndex(name), val);
    }

    public void setParamIndex(String name, Integer index) {
        paramIndexMapping.put(name, index);
    }

    public boolean hasParam(String name) {
        return paramIndexMapping.containsKey(name);
    }

    public Object handle() throws InvocationTargetException, IllegalAccessException, IOException {
        Set<String> authUsers = new HashSet();
        //类级别注解：controller里的所有handler方法都有该级别注解的用户权限
        //方法级别注解：特定handler方法私有的该级别注解的用户权限
        //最终权限是两个级别的并集
        //先判断类级别注解
        if (method.isAnnotationPresent(Security.class)) {
            Security annotation = method.getAnnotation(Security.class);
            for (String user : annotation.value()) {
                authUsers.add(user);
            }
        }
        //方法级别注解
        if (controller.getClass().isAnnotationPresent(Security.class)) {
            Security annotation = controller.getClass().getAnnotation(Security.class);
            for (String user : annotation.value()) {
                authUsers.add(user);
            }
        }

        String authParamName = "username";

        final Object userName = params.getByK1(authParamName);
        if (!authUsers.isEmpty() && !authUsers.contains(userName)) {
            final HttpServletResponse response = (HttpServletResponse) params.getByK1(HttpServletResponse.class.getSimpleName());
            response.setStatus(403);
            response.getWriter().println("user " + userName + " is not allowed to access");
            return null;
        }

        Object[] args = new Object[params.size()];
        for (int i = 0; i < args.length; i++) {
            args[i] = params.getByK2(i);
        }

        return method.invoke(controller, args);
    }

    public Integer getParamIndex(String name) {
        return paramIndexMapping.get(name);
    }
}
